/*
 * @Author: Black / 李来然
 * @Date: 2021-12-14 13:36:04
 * @LastEditors: Black / 李来然
 * @LastEditTime: 2022-01-06 09:57:45
 * @Description: 指纹模块
 */
import { ModsInstance } from '@/func/createMod';
import { getModeFuncRet, RetResult } from "../tools/modHelper";
import { BaseIO } from './baseIO';

export interface FpcState { }
export interface FpcCapability { }

export type FPCfnRet = "FingerDetected" | "FingerTaken";

type FPCfn = (param: RetResult<FPCfnRet>) => void;
type ReadEigenvaluefn = (param: RetResult<FPCfnRet>) => void;

// 获取模板
type FPCRet =
    | "ReadSuccessful"
    | "DeviceError"
    | "FatalError"
    | "FingerDetected"
    | "FingerTaken"
    | "Timeout";

type VerifyRet =
    | "ReadSuccessful"
    | "DeviceError"
    | "FatalError"
    | "DataNotSupport"
    | "DataMissing";

type ResetRet =
    | "ResetComplete"
    | "Timeout"
    | "DeviceError"
    | "FatalError";
type CancelWaitAccept = | "WaitCanceled" | "DeviceError" | "FatalError";

export class Fpc extends BaseIO<FpcState, FpcCapability> {
    private activeMethods = 0;
    constructor(modName: keyof ModsInstance, mod: any) {
        super(modName, mod);
    }

    /**
     * 获取模板
     * @param {number} lTimeout 等待时间
     * @param {string} strPath 模板保存目录
     * @param {function} __call_fn 事件回调  FingerDetected FingerTaken
     * @return Promise
     */
    ReadTemplate(lTimeout: number, strPath: string, __call_fn: FPCfn | null = null) {
        Trace(EC_INFO, '-->Fpc:ReadTemplate');
        this.setCurrentMethod("ReadTemplate");
        this.removeMethodBindEvt("ReadTemplate");
        return new Promise<RetResult<FPCRet>>((resolve, reject) => {
            const ReadSuccessful = (...args: any[]) => {
                Trace(EC_INFO, '<--Fpc:ReadTemplate ReadSuccessful');
                resolve(getModeFuncRet(this.modName, 'ReadSuccessful', args));
            };
            const DeviceError = (...args: any[]) => {
                Trace(EC_INFO, '<--Fpc:ReadTemplate DeviceError');
                resolve(getModeFuncRet(this.modName, 'DeviceError', args));
            };
            const FatalError = (...args: any[]) => {
                Trace(EC_INFO, '<--Fpc:ReadTemplate FatalError');
                resolve(getModeFuncRet(this.modName, 'FatalError', args));
            };
            const FingerDetected = (...args: any[]) => {
                Trace(EC_INFO, '--Fpc:ReadTemplate FingerDetected');
                if (__call_fn)
                    __call_fn(getModeFuncRet(this.modName, "FingerDetected", args));
            };
            const FingerTaken = (...args: any[]) => {
                Trace(EC_INFO, '--Fpc:ReadTemplate FingerTaken');
                if (__call_fn)
                    __call_fn(getModeFuncRet(this.modName, "FingerTaken", args));
            };
            const Timeout = (...args: any[]) => {
                Trace(EC_INFO, '<--Fpc:ReadTemplate Timeout');
                resolve(getModeFuncRet(this.modName, 'Timeout', args));

            };

            this.add('ReadSuccessful', ReadSuccessful);
            this.add('DeviceError', DeviceError);
            this.add('FatalError', FatalError);
            this.add('FingerDetected', FingerDetected);
            this.add('FingerTaken', FingerTaken);
            this.add('Timeout', Timeout);
            this.activeMethods++;
            this.mod.ReadTemplate(lTimeout, strPath, (ret: string) => {
                console.log(lTimeout, strPath);

                if (parseInt(ret) !== 0) {
                    Trace(EC_INFO, `<--Fpc:ReadTemplate ret=${ret}`);
                    resolve(getModeFuncRet(this.modName, "FatalError"));
                }
            });
        }).then((value) => {
            this.activeMethods--;
            this.removeMethodBindEvt("ReadTemplate");
            __call_fn = null;
            return value;
        });
    }

    /**
     * 采集特征值
     * @param {number} lTimeout 等待时间
     * @param {string} strPath 特征值保存目录
     * @param {function} __call_fn 事件回调  FingerDetected FingerTaken
     * @return Promise
     */
    ReadEigenvalue(lTimeout: number, strPath: string, __call_fn: FPCfn | null) {
        Trace(EC_INFO, '-->Fpc:ReadEigenvalue');
        this.setCurrentMethod("ReadEigenvalue");
        this.removeMethodBindEvt("ReadEigenvalue");
        return new Promise<RetResult<FPCRet>>((resolve, reject) => {
            const FingerDetected = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:ReadEigenvalue FingerDetected');
                if (__call_fn)
                    __call_fn(getModeFuncRet(this.modName, "FingerDetected", args));
            };
            const FingerTaken = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:ReadEigenvalue FingerTaken');
                if (__call_fn)
                    __call_fn(getModeFuncRet(this.modName, "FingerTaken", args));
            };
            const ReadSuccessful = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:ReadEigenvalue ReadSuccessful');
                resolve(getModeFuncRet(this.modName, "ReadSuccessful", args));
            };
            const DeviceError = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:ReadEigenvalue DeviceError');
                resolve(getModeFuncRet(this.modName, "DeviceError", args));
            };
            const FatalError = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:ReadEigenvalue FatalError');
                resolve(getModeFuncRet(this.modName, "FatalError", args));
            };
            const Timeout = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:ReadEigenvalue Timeout');
                resolve(getModeFuncRet(this.modName, "Timeout", args));
            };

            // this.addDeviceTimOut();
            this.add('FingerDetected', FingerDetected);
            this.add('FingerTaken', FingerTaken);
            this.add('ReadSuccessful', ReadSuccessful);
            this.add('DeviceError', DeviceError);
            this.add('FatalError', FatalError);
            this.add('Timeout', Timeout);

            this.activeMethods++;
            this.mod.ReadEigenvalue(lTimeout, strPath, (ret: string) => {
                if (parseInt(ret) !== 0) {
                    Trace(EC_INFO, `<--Fpc:ReadEigenvalue ret=${ret}`);
                    resolve(getModeFuncRet(this.modName, "FatalError"));
                }
            });
        }).then((value) => {
            this.activeMethods--;
            this.removeMethodBindEvt("ReadEigenvalue");
            __call_fn = null;
            return value;
        });
    }

    /**
     * 获取特征值
     * @return Promise
     */
    GetEigenvalueSync() {
        Trace(EC_INFO, '-->Fpc:GetEigenvalueSync');
        this.setCurrentMethod("GetEigenvalueSync");
        this.removeMethodBindEvt("GetEigenvalueSync");
        return new Promise((resolve, reject) => {
            this.mod.GetEigenvalueSync((ret: any) => {
                resolve(ret);
            });
        }).then((value: any) => {
            this.removeMethodBindEvt("GetEigenvalueSync");
            return value;
        });
    }

    /**
     * 校验
     * @param {string} strPath 特征值保存目录
     * @return Promise
     */
    Verify(paths: string[]) {
        Trace(EC_INFO, '-->Fpc:Verify');
        this.setCurrentMethod("Verify");
        this.removeMethodBindEvt("Verify");
        let m = new Map<VerifyRet, RetResult<VerifyRet>>();
        let that = this;
        let count = 0;

        

        return new Promise<RetResult<VerifyRet>>((resolve, reject) => {
            let that = this;
            function setResult(evtName: VerifyRet, args: any[]) {
                that.activeMethods--;
                count++;
                if(evtName === 'ReadSuccessful') {
                    resolve(getModeFuncRet(that.modName, evtName, args));
                    return;
                }
                if (!m.has(evtName)) {
                    m.set(evtName, getModeFuncRet(that.modName, evtName, args))
                }
                if (count === paths.length) {
                    let arr: VerifyRet[] = ['DeviceError', 'FatalError', 'DataMissing', 'DataNotSupport']
                    resolve(getRet(m, arr));
                }
            }
            const ReadSuccessful = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:Verify ReadSuccessful');
                // resolve(getModeFuncRet(this.modName, "ReadSuccessful", args));
                // this.CancelWaitAccept();
                setResult('ReadSuccessful', args)
            };
            const DeviceError = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:Verify DeviceError');
                // resolve(getModeFuncRet(this.modName, "DeviceError", args));
                setResult('DeviceError', args)
            };
            const FatalError = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:Verify FatalError');
                // resolve(getModeFuncRet(this.modName, "DeviceError", args));
                setResult('FatalError', args)
            };
            const DataNotSupport = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:Verify DataNotSupport');
                // resolve(getModeFuncRet(this.modName, "DeviceError", args));
                setResult('DataNotSupport', args)
            };
            const DataMissing = (...args: any[]) => {
                // this.ClearCtrTimout();
                Trace(EC_INFO, '<--Fpc:Verify DataMissing');
                // resolve(getModeFuncRet(this.modName, "DeviceError", args));
                setResult('DataMissing', args)
            };

            // this.addDeviceTimOut();
            this.add('ReadSuccessful', ReadSuccessful);
            this.add('DeviceError', DeviceError);
            this.add('FatalError', FatalError);
            this.add('DataNotSupport', DataNotSupport);
            this.add('DataMissing', DataMissing);

            function getRet(mp: Map<VerifyRet, RetResult<VerifyRet>>, evtNames: VerifyRet[]): RetResult<VerifyRet> {
                let evtName = evtNames.shift();
                if (evtName !== undefined) {
                    let ret = mp.get(evtName);
                    if (ret) {
                        return ret;
                    }
                    return getRet(mp, evtNames);
                } else {
                    return getModeFuncRet(that.modName, "FatalError", [])
                }
            }

            for (const strPath of paths) {
                this.activeMethods++;
                this.mod.Verify(strPath, (ret: string) => {
                    console.log(`${strPath}模板`);
                    if (parseInt(ret) !== 0) {
                        Trace(EC_INFO, `<--Fpc:Verify ret=${ret}`);
                        resolve(getModeFuncRet(this.modName, "FatalError"));
                    }
                });
            }


        }).then((value) => {
            this.removeMethodBindEvt("Verify");
            console.log(value);
            return value;
        });
    }

    /**
     * 取消等待
     * @return Promise
     */
    CancelWaitAccept() {
        Trace(EC_INFO, '-->Fpc:CancelWaitAccept');
        this.setCurrentMethod("CancelWaitAccept");
        this.removeMethodBindEvt("CancelWaitAccept");
        if(this.activeMethods === 0){
            return Promise.resolve(getModeFuncRet(this.modName, "WaitCanceled", []))
        }
        return new Promise<RetResult<CancelWaitAccept>>((resolve, reject) => {
            const WaitCanceled = (...args: any[]) => {
                Trace(EC_INFO, '<--Fpc:CancelWaitAccept WaitCanceled');
                resolve(getModeFuncRet(this.modName, "WaitCanceled", args));
            };
            const DeviceError = (...args: any[]) => {
                Trace(EC_INFO, '<--Fpc:CancelWaitAccept DeviceError');
                resolve(getModeFuncRet(this.modName, "DeviceError", args));
            };
            const FatalError = (...args: any[]) => {
                Trace(EC_INFO, '<--Fpc:CancelWaitAccept FatalError');
                resolve(getModeFuncRet(this.modName, "FatalError", args));
            };

            this.add('WaitCanceled', WaitCanceled);
            this.add('DeviceError', DeviceError);
            this.add('FatalError', FatalError);

            this.mod.CancelWaitAccept((ret: string) => {
                if (parseInt(ret) !== 0) {
                    Trace(EC_INFO, `<--Fpc:CancelWaitAccept ret=${ret}`);
                    resolve(getModeFuncRet(this.modName, "FatalError"));
                }
            });
        }).then((value) => {
            this.activeMethods--;
            this.removeMethodBindEvt("CancelWaitAccept");
            return value;
        });
    }

    /**
     * 重置
     */
    Reset() {
        Trace(EC_INFO, '-->Fpc:Reset');
        this.setCurrentMethod("Reset");
        this.removeMethodBindEvt("Reset");
        return new Promise<RetResult<ResetRet>>((resolve, reject) => {
            const ResetComplete = (...args: any[]) => {
                Trace(EC_INFO, '<--Crd:Reset ResetComplete');
                resolve(getModeFuncRet(this.modName, "ResetComplete", args));
            };
            const Timeout = (...args: any[]) => {
                Trace(EC_INFO, '<--Crd:Reset Timeout');
                resolve(getModeFuncRet(this.modName, "Timeout", args));
            };
            const DeviceError = (...args: any[]) => {
                Trace(EC_INFO, '<--Crd:Reset DeviceError');
                resolve(getModeFuncRet(this.modName, "DeviceError", args));
            };
            const FatalError = (...args: any[]) => {
                Trace(EC_INFO, '<--Crd:Reset FatalError');
                resolve(getModeFuncRet(this.modName, "FatalError", args));
            };

            this.add('ResetComplete', ResetComplete);
            this.add('Timeout', Timeout);
            this.add('DeviceError', DeviceError);
            this.add('FatalError', FatalError);

            this.mod.Reset((ret: string) => {
                if (parseInt(ret) !== 0) {
                    Trace(EC_INFO, '<--Crd:Reset ret=' + ret);
                    resolve(getModeFuncRet(this.modName, "FatalError"));
                }
            });
        }).then((value) => {
            this.removeMethodBindEvt("Reset");
            return value;
        });
    }
}
